﻿using System;
using System.IO;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Services.FileSystem;

namespace BrandonHaynes.Providers.AmazonS3
	{
	/// <summary>
	/// Class representing a DotNetNuke S3-enabled file
	/// </summary>
	public class S3File
		{
		// The second-high bit on a 32-bit integer is used it mark S3 files.
		//   This implies that the provider will violently explode after the 2^30th = 1,073,741,824 file
		// is persisted on any installation (this includes files that are stored and later deleted).
		//   Note also that the DotNetNuke core chokes when provided with a negative identifier, so
		// we are out of luck using the high bit.  Indeed, this bit must be explicitly cleared when
		// generating identifiers for our S3 files.
		private const int S3FileIdentifyingBit = 0x40000000;

		/// <summary>
		/// Generates a S3 identifier by utilizing the hashcode of the file name, 
		/// clearing the high-order bit and setting the identifying bit.
		/// 
		/// Note that we are using string.GetHashCode() here, which does not provide full
		/// assurance of even distribution, and we are sure to experience collisions in our
		/// 2^30 space.  We could use the low-30 of a HMAC (e.g., SHA-1) for additional entropy,
		/// but this would also introduce additional computational overhead.  Here, the hash code
		/// seems an appropriate blend of efficiency and distribution.
		/// 
		/// If you happen to collide, which is expected occur with exceeding rarity, change your
		/// S3 filename.  We otherwise assume no collisions.
		/// </summary>
		/// <param name="name">The name of the file for which to generate an identifier</param>
		/// <returns>An integer identifier for the file with low probability of collision</returns>
		internal static int MakeId(string name)
			{ return (name.GetHashCode() & 0x7FFFFFFF) | S3FileIdentifyingBit; }

		/// <summary>
		/// Given a file identifier, determines if this is a S3 file (identified by the S3 bit)
		/// </summary>
		public static bool IsS3File(int fileId)
			{ return (fileId & S3FileIdentifyingBit) != 0; }

		private long fileId;
		/// <summary>
		/// Gets or sets the identifier associated with this object; when set, the S3-identifying
		/// bit is set on any supplied value (this prevents accidential inconsistant state).
		/// </summary>
		public long FileID
			{ 
			get { return fileId; }
			set { fileId = value | S3FileIdentifyingBit; }
			}
		public int PortalID { get; set; }
		public string FileName { get; set; }
		public long Size { get; set; }
		public int Width { get; set; }
		public int Height { get; set; }
		public int FolderID { get; set; }
		public string Folder { get; set; }

		public string Extension { get { return Path.GetExtension(FileName).TrimStart('.'); } }
		public string ContentType { get { return FileSystemUtils.GetContentType(Extension); } }
		public FolderController.StorageLocationTypes StorageLocation { get { return FolderController.StorageLocationTypes.DatabaseSecure; } }
		public bool IsCached { get { return false; } }
		public Byte[] Content { get; set; }
		}
	}
